// Copyright (c) Appeon. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

using System;
using System.IO;

namespace SnapObjects.Commons
{
    public class CharacterReader : IDisposable
    {
        private readonly IBufferedTextReader _inputStream = null;
        private bool _hasMore = true;
        private bool _hasExtra = false;
        private char _extraChar;

        public CharacterReader(string value) : this(new StringReader(value))
        {

        }

        public CharacterReader(TextReader inputStream)
        {
            _inputStream = new BufferedTextReader(inputStream);

            this.Position = -1;
        }

        public bool Read()
        {
            if (_hasMore)
            {
                if (_hasExtra)
                {
                    this.Current = _extraChar;
                    _hasExtra = false;
                }
                else
                {
                    _hasMore = _inputStream.MoveNext();
                    if (_hasMore)
                    {
                        this.Current = _inputStream.Current;
                        this.Position++;
                    }
                    else
                    {
                        this.Current = Char.MinValue;
                    }
                }
            }

            return _hasMore;
        }

        public bool ReadNextNonWhitespace()
        {
            bool hasNext;

            do
            {
                hasNext = this.Read();
            } while (hasNext && Char.IsWhiteSpace(this.Current));

            return hasNext;
        }

        public void Putback()
        {
            _hasExtra = true;
            _extraChar = this.Current;
            _hasMore = true;
        }

        public char Current { get; private set; }

        public int Position { get; private set; }

        public bool EOF => !_hasMore;

        public void Dispose()
        {
            if (_inputStream != null)
            {
                _inputStream.Dispose();
            }
        }
    }
}
